package com.huige.wiki.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.huige.wiki.entity.Content;
import com.huige.wiki.entity.Doc;
import com.huige.wiki.entity.DocExample;
import com.huige.wiki.exception.BusinessException;
import com.huige.wiki.exception.BusinessExceptionCode;
import com.huige.wiki.mapper.ContentMapper;
import com.huige.wiki.mapper.DocMapper;
import com.huige.wiki.mapper.DocMapperCust;
import com.huige.wiki.req.DocQueryReq;
import com.huige.wiki.req.DocSaveReq;
import com.huige.wiki.resp.DocQueryResp;
import com.huige.wiki.resp.PageResp;
import com.huige.wiki.service.DocService;
import com.huige.wiki.util.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Slf4j
public class DocServiceImpl implements DocService {

    @Autowired
    DocMapper docMapper;

    @Autowired
    ContentMapper contentMapper;
    @Autowired
    SnowFlake snowFlake;  // 雪花算法工具类

    @Autowired
    DocMapperCust docMapperCust;

    @Autowired
    RedisUtil redisUtil;

    @Resource
    public WsService wsService;

    /**
     * 分页查询文档数据。暂时用不到，文档展示树形表格，要把所有数据都返回
     * @param docQueryReq
     * @return
     */
    @Override
    public PageResp<DocQueryResp> list(DocQueryReq docQueryReq) {
        // 创建一个条件查询
        DocExample docExample = new DocExample();
        DocExample.Criteria criteria = docExample.createCriteria();
        // 设置排序:按sort字段升序排序
        docExample.setOrderByClause("sort asc");
//        if(!ObjectUtils.isEmpty(docQueryReq.getName())){
//            criteria.andNameLike("%"+docQueryReq.getName()+"%");
//        }
//        if(!ObjectUtils.isEmpty(docQueryReq.getDocId2())){
//            criteria.andDoc2IdEqualTo(docQueryReq.getDocId2());
//        }
        //设置分页参数
        PageHelper.startPage(docQueryReq.getPage(), docQueryReq.getSize());
        List<Doc> docs = docMapper.selectByExample(docExample);
        // 将查询结果封装到PageInfo对象中
        PageInfo<Doc> docPageInfo = new PageInfo<>(docs);
        // 将Doc对象列表转换为DocQueryResp对象列表
        List<DocQueryResp> list = CopyUtil.copyList(docs, DocQueryResp.class);

        // 将PageInfo对象中的数据封装到PageResp对象中
        PageResp<DocQueryResp> pageResp = new PageResp<>();
        pageResp.setTotal(docPageInfo.getTotal());
        pageResp.setList(list);

        return pageResp;

    }

    /**
     * 查询所有文档数据。前端要展示树形表格，所有要查所有
     * @param
     * @return
     */
    @Override
    public List<DocQueryResp> all(Long ebookId) {
        // 创建一个条件查询
        DocExample docExample = new DocExample();
        // 设置排序:按sort字段升序排序
        DocExample.Criteria criteria = docExample.createCriteria();
        criteria.andEbookIdEqualTo(ebookId);
        docExample.setOrderByClause("sort asc");

        List<Doc> docs = docMapper.selectByExample(docExample);

        // 将Doc对象列表转换为DocQueryResp对象列表
        List<DocQueryResp> list = CopyUtil.copyList(docs, DocQueryResp.class);

        return list;
    }

    /**
     * 保存电子书(新增或者修改)
     * @param docQueryReq
     */
    @Override
    public void save(DocSaveReq docQueryReq) {
        Doc doc = CopyUtil.copy(docQueryReq, Doc.class);
        Content content = CopyUtil.copy(docQueryReq, Content.class);
        if(ObjectUtils.isEmpty(doc.getId())){
            // 如果id为空，则新增
            doc.setId(snowFlake.nextId());
            // 新增文档时，阅读数和点赞数都是0
            doc.setViewCount(0);
            doc.setVoteCount(0);
            docMapper.insert(doc);
            // content表和doc表用的是同一个id
            content.setId(doc.getId());
            contentMapper.insert(content);
        }else{
            // 如果id不为空，则修改
            int count1 = docMapper.updateByPrimaryKey(doc);
            // 更新大字段需要使用updateByPrimaryKeyWithBLOBs
            int count2 = contentMapper.updateByPrimaryKeyWithBLOBs(content);

            // 可以更新文档表成功，但是更新文档内容表失败，说明文档表有数据，文档内容表没有数据
            // 出现这个问题一般在于初始化得那几条数据中
            if(count1!=0 && count2==0){
                contentMapper.insert(content);
            }
        }
    }

    @Override
    public void delete(Long id) {
        docMapper.deleteByPrimaryKey(id);
    }

    /**
     * 批量删除文档：因为删除文档时，需要把该文档以及所有子文档全部删除
     * 前端传过来的数据就是该文档以及所有子文档的id
     * @param idsStr
     */
    @Override
    public void delete(String idsStr) {
        List<Long>ids = new ArrayList<>();
        if(StringUtils.isNotEmpty(idsStr)){
            ids = Arrays.asList(idsStr.split(",")).stream().map(id->Long.parseLong(id)).collect(Collectors.toList());
        }
        DocExample docExample = new DocExample();
        DocExample.Criteria criteria = docExample.createCriteria();
        criteria.andIdIn(ids);
        docMapper.deleteByExample(docExample);
    }

    /**
     * 用户根据指定id查找文档
     * @param id
     * @return
     */
    @Override
    public String findContent(Long id) {
        Content content = contentMapper.selectByPrimaryKey(id);
        // 防止空指针异常，根据id查文档内容，文档有，一般文档内容也有。出问题的在于初始化那几条数据
        if (ObjectUtils.isEmpty(content)) return "";

        // 文档阅读数+1
        docMapperCust.increaseViewCount(id);
        return content.getContent();
    }

    /**
     * 给指定文档点赞
     * @param id
     */
    @Override
    public void vote(Long id) {
        // 远程ip+doc作为key,24小时内不能重复
        // 也就是同一台设备一天只能对一篇文档点赞一次
        String key = "DOC_VOTE_"+id+"_"+ RequestContext.getRemoteAddr();
        if(redisUtil.validateRepeat(key,3600*24)){
            // 点赞数+
            docMapperCust.increaseVoteCount(id);
        }else{
            throw new BusinessException(BusinessExceptionCode.VOTE_REPEAT);
        }

        // 推送消息
        Doc docDb = docMapper.selectByPrimaryKey(id);
        String logId = MDC.get("LOG_ID");
        wsService.sendInfo("【" + docDb.getName() + "】此刻被赞了一下", logId);

    }

    @Override
    public void updateEbookInfo() {
        docMapperCust.updateEbookInfo();
    }
}
